package com.mofang.ticketing.common.web.core.feign;

import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.TypeFactory;
import com.mofang.ticketing.common.core.exception.BizException;
import com.mofang.ticketing.common.core.result.Result;
import feign.Response;
import feign.codec.Decoder;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;

import java.io.IOException;
import java.io.Reader;
import java.lang.reflect.Type;
import java.nio.charset.Charset;

/**
 * 每个 Feign 的接口处定义同样的类比如 Result<XxVO> 再 getData() 不是不行，但是比较繁琐，
 * 而且在获取想要的数据前可能需要根据 code、message 判断得到的结果是否符合正确。
 * 通过自定义 decoder 可以比较好地解决前一个问题
 * <p>
 * 这里完成自动解包Result，成功直接获取data具体数据
 * 如果这里执行出错，这里会报 DecodeException
 */
@RequiredArgsConstructor
public class UnwrapDecoder implements Decoder {

    private final ObjectMapper objectMapper;

    @SneakyThrows
    @Override
    public Object decode(Response response, Type type) {
        Reader reader = response.body().asReader(Charset.defaultCharset());
        //controller 返回必须是Result 不然会抛出异常
        Result<?> result = objectMapper.readValue(reader, Result.class);
        // 根据 code 判断操作是否成功， client 无需使用 Result<XxVO> 泛型包装，业务中直接调用
        if (Result.isSuccess(result)) {
            Object data = result.getData();
            JavaType javaType = TypeFactory.defaultInstance().constructType(type);
            return objectMapper.convertValue(data, javaType);
        }
        // 若不成功，抛出业务异常，注意此处的异常会在 DecodeException 中被捕获，后文会处理
        throw new BizException(result.getCode(), result.getMsg());
    }
}
